﻿#pragma once
#ifndef VF_APIUTILS_H
#define VF_APIUTILS_H
#include <VFAdapterAPIs.h>
#include <boost/bimap.hpp>

namespace VFAdapter {

struct PersistIDManager {
public:
  //!
  //! @brief 查询拓扑ID
  //!
  //! @param pEnt
  //! @return uint32_t
  //!
  uint32_t GetEntityID(IDispatchPtr const &pEnt);

  //!
  //! @brief 由ID查询到拓扑对象
  //!
  //! @param id
  //! @return IDispatchPtr
  //!
  IDispatchPtr FindEntityByID(uint32_t id) const;
  PersistIDManager(_bstr_t const &fileFullName, IStoragePtr const &pAddInStg,
                   IStoragePtr const &pStg);

  //!
  //! @brief 从存储中读取数据
  //!
  //! @return true
  //! @return false
  //!
  bool ReadFromStorage();

  //!
  //! @brief 记录此管理器管理的对象
  //!
  //! @return _bstr_t
  //!
  _bstr_t GetFullName() const { return m_fileFullName; }

  static bool GetManager(std::shared_ptr<PersistIDManager> &pMng,
                         fw::SolidEdgeDocumentPtr pDoc);

private:
  IStoragePtr m_pAddInStg = nullptr;
  IStoragePtr m_pStg = nullptr;
  _bstr_t m_fileFullName;
  boost::bimaps::bimap<std::vector<BYTE>, uint32_t> m_idMap;

private:
  //!
  //! @brief 将数据写入存储
  //!
  //! @param key
  //! @param id
  //! @return true
  //! @return false
  //!
  bool WriteToStream(std::vector<BYTE> const &key, uint32_t id) const;

  //!
  //! @brief 获得Key，Key本质为字节数组(非字符串)
  //!
  //! @param pKeyArr
  //! @param pEnt
  //! @return true
  //! @return false
  //!
  bool GetReferenceKey(LPSAFEARRAY &pKeyArr, LPDISPATCH pEnt) const;

  ATL::CComSafeArray<BYTE> ByteArrToKey(std::vector<BYTE> const &vec) const;
  std::vector<BYTE> KeyToByteArray(LPSAFEARRAY pKey) const;

  static bool ExistStorage(IStoragePtr &pAddInStg, IStoragePtr &pStg,
                           const wchar_t *addInStgName,
                           fw::SolidEdgeDocumentPtr pDoc);
  static bool CreateStorage(IStoragePtr &pAddInStg, IStoragePtr &pStg,
                            const wchar_t *addInStgName,
                            fw::SolidEdgeDocumentPtr pDoc);
};

struct ApiUtils {
  // 用初始化列表的方式形成com数组
  template <typename T>
  static ATL::CComSafeArray<T>
  ToComSafeArray(std::initializer_list<T> const &initial_list) {
    ATL::CComSafeArray<T> comArray((ULONG)initial_list.size());
    long i = 0;
    for (auto it = initial_list.begin(); it != initial_list.end(); ++it) {
      comArray.SetAt(i, *it);
      i++;
    }
    return comArray;
  }

  // 获得第一个三维草图、如无三维草图，则创建
  static pt::Sketch3DPtr GetFirstSketch3D();

  //!
  //! @brief 获得一个实体(特征或拓扑)的Type属性
  //!
  //! @param pGraphicDispatch
  //! @param nObjectType 其为一串整形数字
  //! @return HRESULT
  //!
  static HRESULT GetLocatedGraphicType(LPDISPATCH pGraphicDispatch,
                                       int &nObjectType);

  //!
  //! @brief 获得某个对象的指定属性
  //!
  //! @param varRes 得到的属性
  //! @param pObj  对象
  //! @param propName 属性名
  //! @return HRESULT
  //!
  static HRESULT GetDispProperty(_variant_t &varRes, LPDISPATCH pObj,
                                 _bstr_t const &propName);

  static IDispatchPtr GetParent(LPDISPATCH pObj);

  //!
  //! @brief 调用删除方法
  //!
  //! @param pObj
  //!
  static HRESULT InvokeDelete(LPDISPATCH pObj);

  static HRESULT GetEdges(_variant_t &varRes, int queryType, LPDISPATCH pObj);

  // 通过ID获得拓扑实体后，继而获得他的Type属性
  static vfHRESULT GetObjType(int &objType, long ObjID);

  //!
  //! @brief 任意实体，如非拓扑类型，返回none，否则返回具体是
  // 点、边、面、体中的一种
  //!
  //! @param pDisp
  //! @return geom_entity_type
  //!
  static geom_entity_type GetGeomType(LPDISPATCH pDisp);

  // 枚举类型转换
  static geom_entity_type ToEntityType(int objType);

  //!
  //! @brief 由ID查找得拓扑实体
  //!
  //! @param entID
  //! @return IDispatchPtr
  //!
  static IDispatchPtr FindEntityByID(int64_t entID);
  static IDispatchPtr FindEntityByID(const char *entID);

  //!
  //! @brief 获得拓扑实体ID
  //!
  //! @param pEnt
  //! @return int64_t
  //!
  static int64_t GetEntityID(IDispatchPtr const &pEnt);
  static const char *GetEntityIDString(IDispatchPtr const &pEnt);

  //!
  //! @brief 获得特征实体ID
  //!
  //! @param pEnt
  //! @return int64_t
  //!
  static int64_t GetFeatureID(IDispatchPtr const &pEnt);

  //!
  //! @brief 由ID查找到特征实体
  //!
  //! @param objID
  //! @return IDispatchPtr
  //!
  static IDispatchPtr FindFeatureByID(int64_t objID);
  static IDispatchPtr FindFeatureByID(const char *objID);

  static IDispatchPtr EntityToGeomtry(IDispatchPtr const &pEnt,
                                      int64_t ptIDX = UINT64_MAX);

  static int64_t GetEdgeSegmentID(IDispatchPtr const &pEdge);

  //!
  //! @brief 由几何类型映射筛选类型
  //!
  //! @param geomType
  //! @return int
  //!
  static int ConvertToFilterType(geom_entity_type geomType);

  //!
  //! @brief 当前选择集中是否已有指定实体
  //!
  //! @param entityIDs 返回的符合正确类型的实体ID集
  //! @param geoType   待查找的实体类型
  //! @return vfHRESULT entityIDs非空时 Success，否则 Failure
  //!
  static bool HasEntityInSelectionSet(std::vector<int64_t> &entityIDs,
                                      int geoType);

  //!
  //! @brief 查找某窗口下的所有WPF子窗口
  //!
  //! @param hwndParent 父窗口
  //! @param destWpfWindows 存放所有WPF子窗口的容器
  //!
  static void FindWpfWindows(HWND hwndParent,
                             std::unordered_set<HWND> *destWpfWindows);

  //!
  //! @brief 查找或创建高亮集
  //!
  //! @param color    高亮颜色
  //! @param width    线宽
  //! @param forceCreateNew 高亮集是否强制创建一个新的
  //!
  static fw::HighlightSetPtr
  FindOrCreateFstHighlightSet(long color = RGB(0, 255, 0), int width = 4,
                              bool forceCreateNew = false);

  static HRESULT ThickenAndHighlight(fw::HighlightSetPtr const &pHighlightSet,
                                     std::vector<int64_t> const &entIdArr);

  //!
  //! @brief
  //!
  //! @param entIdArr 要高亮的实体ID集
  //! @param color    高亮颜色
  //! @param width    线宽
  //! @param forceCreateNew 高亮集是否强制创建一个新的
  //! @return HRESULT
  //!
  static HRESULT ThickenAndHighlight(std::vector<int64_t> const &entIdArr,
                                     long color = RGB(0, 255, 0), int width = 4,
                                     bool forceCreateNew = false);

  //!
  //! @brief 清除加粗和高亮
  //!
  //! @return HRESULT
  //!
  static HRESULT ClearThickenAndHighlight(std::vector<int64_t> const &entIdArr);

  //!
  //! @brief 由草图3D上曲线的拓扑边得到曲线实体
  //!
  //! @param pEdge
  //! @return IDispatchPtr
  //!
  static IDispatchPtr Sketch3dTopoToObject(gm::EdgePtr pEdge);

  //!
  //! @brief 获取线的长度
  //!
  //! @param pEdge
  //! @param length
  //! @return true
  //! @return false
  //!
  static bool GetEdgeLength(gm::EdgePtr pEdge, double &length);

  // 计算向量模长
  static double magnitude(const double vec[3]);

  // 归一化向量（结果写入 result 数组）
  static void normalized(const double vec[3], double result[3]);

  // 计算点积
  static double dot(const double v1[3], const double v2[3]);

  // 计算叉乘（结果写入 result 数组）
  static void cross(const double v1[3], const double v2[3], double result[3]);

  /// 方法1: 叉乘法找垂直向量（结果写入 result 数组）
  static void findPerpendicularCross(const double vec[3], double result[3]);

  // 函数：两个三维向量相加
  static void vectorAdd(const double a[3], const double b[3], double result[3]);

  //!
  //! @brief 查找点在哪个面组中的哪个面上
  //!
  //! @param x
  //! @param y
  //! @param z
  //! @param pFaces
  //! @return gm::FacePtr 返回为Nullptr时，不在任一面上。
  //!
  static gm::FacePtr FindPointOnFace(double x, double y, double z,
                                     gm::FacesPtr pFaces);

  //!
  //! @brief  从字符串中收集得实体ID集
  //!
  //! @param inputStringValue
  //! @return std::vector<int64_t>
  //!
  static std::vector<int64_t> CollectIds(const char *inputStringValue[]);

  //!
  //! @brief  递归删除特征及其父特征
  //!
  //! @param pObj
  //!
  static void DelFeatureRecursive(pt::PartDocumentPtr const &pPartDoc,
                                  IDispatchPtr const &pObj);

  //!
  //! @brief 取三维草图曲线实体集的拓扑边集
  //!
  //! @param pCvDispArr
  //! @return gm::EdgesPtr
  //!
  static gm::EdgesPtr ExtractTopoEdges(LPSAFEARRAY pCvDispArr);
};

}; // namespace VFAdapter

#endif